﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
using System.Resources;

namespace MvePublicService.ClipOperations
{
	/*
	 * 日本SGI株式会社
	 * ヨハンソン・ヘンリク
	 * johansson@sgi.co.jp
	 * 
	 * Change Log:
	 * ---------------------------------------------------------------------------
	 * 2009.01.06	Johansson Henrik		Class Created.
	 * 2009.01.07							Updated GetClip to use the various Loader classes.
	 *										Those Updates have not been Tested yet.
	 * 2009.01.09							Updated GetCLip to always return an XML string.
	 *										Currently the application expect the reply to be an Error
	 *										Xml Document (status = 1) even if an exception is thrown
	 *										or no matching data was founds.
	 */

	/// <summary>
	/// This static class provides methods for extracting, 
	/// updating and deleting Clips and Segments in the Database.
	/// Use the static methods in this class to perform Clip and 
	/// Segment related operations on the Database.
	/// </summary>
	/// <remarks>INSERT:Creds</remarks>
	internal static class ClipManipulator
	{
		/// <summary>
		/// Gets all the Clips registered for the given User Id.
		/// </summary>
		/// <remarks>Not Implemented. Was never called in original Service.</remarks>
		internal static string QueryClipsForUser(int userId, SqlConnection connection)
		{
			throw new NotImplementedException(
				MvePublicService.Properties.Resources.NotImplementedInOriginal);

		}//end:QueryClipsForUser

		/// <summary>
		/// Get all the Segments that make up a given clip, given a clip Id.
		/// </summary>
		/// <remarks>Not Implemented. Was never called in original Service.</remarks>
		internal static string GetClipSegments(int clipId, SqlConnection connection)
		{
			throw new NotImplementedException(
				MvePublicService.Properties.Resources.NotImplementedInOriginal);
		}//end:GetClipSegments

		/// <summary>
		/// Get a single clip out of the DB
		/// Original Name = Clip
		/// </summary>
		/// <remarks>Done</remarks>
		/// <param name="clipId">Id of the Clip to pull from the DB</param>
		/// <param name="connection">Sql Connection</param>
		/// <returns>The Xml string that contains the response document.</returns>
		internal static string GetClip(int clipId, SqlConnection connection)
		{

			string result = string.Empty;
			try
			{
				Dictionary<Segment, List<KeywordOperations.Keyword>> segmentKeywords =
					new Dictionary<Segment, List<KeywordOperations.Keyword>>();

				Clip parentClip = ClipLoader.LoadClipFromDatabase(clipId, connection);
				if (parentClip == null)
					throw new ArgumentNullException("The parentClip is null (not found?)");

				List<Segment> segments =
					SegmentLoader.LoadSegmentsForClipFromDatabase(parentClip.Id, connection);

				//There might be Clips with no segments?
				if (segments != null)
				{
					foreach (Segment seg in segments)
					{
						List<KeywordOperations.Keyword> segKeywords =
							KeywordOperations.KeywordLoader.LoadKeywordsForSegmentFromDatabase(
									seg.Id, connection);

						//There might be Segments with no keywords?
						if (segKeywords != null)
							segmentKeywords.Add(seg, segKeywords);
						else
							segmentKeywords.Add(seg, new List<KeywordOperations.Keyword>());
					}

				}

				//If we made it here we have all the data needed to build a complete clip response
				//Next, build the Xml Document.
				XmlDocument doc = null;
				XmlElement dataRoot = XmlConstructor.FormatResponseDocument(ref doc);

				XmlElement clipRoot = XmlConstructor.AddClipNodeToDocument(doc, parentClip, dataRoot);
				foreach (KeyValuePair<Segment, List<KeywordOperations.Keyword>>
					kvSegKey in segmentKeywords)
				{

					XmlElement segmentRoot = XmlConstructor.AddSegmentNodeToClip(
						doc, kvSegKey.Key, parentClip.OnAirDate, clipRoot);

					if (kvSegKey.Value.Count != 0)
					{
						XmlElement kwRoot = doc.CreateElement("keywords");
						segmentRoot.AppendChild(kwRoot);

						foreach (KeywordOperations.Keyword keyword in kvSegKey.Value)
						{
							XmlConstructor.AddKeywordNodeToSegment(
								doc, keyword, kwRoot);
						}
					}
				}

				result = doc.OuterXml;

			}
			catch (Exception ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				result =
					XmlConstructor.GetOperationFailedResponseDocument().OuterXml;
			}

			return result;
		}//end:GetClip

		/// <summary>
		/// Gets the parent Clip of a segment, given a segment Id. This method
		/// first gets the Segment out of the segment table, pulls out its clip_id
		/// value and then calls GetClip with the clip_id value.
		/// Original Name = ClipBySegmentId
		/// </summary>
		/// <remarks>Done</remarks>
		/// <param name="segmentId">Id of the segment whose parent clip to retreive</param>
		/// <param name="connection">Sql Connection</param>
		/// <returns>The Xml string that contains the response document.</returns>
		internal static string GetClipBySegmentId(int segmentId, SqlConnection connection)
		{
			SqlCommand command = new SqlCommand();
			SqlDataReader reader = null;
			command.CommandTimeout = 60;

			int? parentClipId = null;

			string result = string.Empty;
			try
			{
				command.Connection = connection;
				command.CommandType = System.Data.CommandType.StoredProcedure;
				command.CommandText = "GetSegmentById";

				command.Parameters.Add("segmentId", SqlDbType.Int).Value = segmentId;
				reader = command.ExecuteReader();

				if (reader.HasRows)
				{
					reader.Read();
					parentClipId = reader.GetInt32(1);
				}


				command.Dispose();
				reader.Close();
				reader.Dispose();

				string clipResult = string.Empty;
				if (parentClipId.HasValue)
				{
					clipResult = ClipManipulator.GetClip(parentClipId.Value, connection);
					if (string.IsNullOrEmpty(clipResult) == false)
						result = clipResult;
				}

			}
			catch (NullReferenceException ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				result = string.Empty;
			}
			catch (SqlException ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				result = string.Empty;
			}
			catch (InvalidOperationException ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				result = string.Empty;
			}
			catch (IndexOutOfRangeException ex)
			{
				MvePublicService.ErrorHandler.LogMessage(ex.Message, false);
				result = string.Empty;
			}
			finally
			{
				command.Dispose();
				if (reader != null)
				{
					reader.Close();
					reader.Dispose();
				}
			}

			return result;
		}//end:GetClipBySegmentId
	}
}
